frint-store
Store package of Frint
Guide
Installation
With npm:
$ npm install --save frint-store
Via unpkg CDN:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>
<script src="https://unpkg.com/frint-store@latest/dist/frint-store.min.js"></script>
<script>
</script>
Terminologies
Store
: The object that holds state, with additional methods.State
: Plain object that holds the state.Action
: A plain object/payload telling Store to do something.Action Type
: All action payloads are required to have a type
key.Action Creator
: A function that returns the Action payload.Reducer
: Function that returns a new updated state based on Action.
Usage
Let's import the necessary functions from the library first:
const Frint = require('frint');
const { createStore, combineReducers } = Frint;
We can start by defining our Action Types:
const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
Then we can proceed with writing our Action Creator functions:
function incrementCounter() {
return {
type: INCREMENT_COUNTER
};
}
function decrementCounter() {
return {
type: DECREMENT_COUNTER
};
}
Let's follow up with a Reducer now:
const INITIAL_COUNTER_STATE = {
value: 0
};
function counterReducer(state = INITIAL_COUNTER_STATE, action) {
switch (action.type) {
case 'INCREMENT_COUNTER':
return Object.assign({}, {
value: state.value + 1
});
case 'DECREMENT_COUNTER':
return Object.assign({}, {
value: state.value - 1
});
default:
return state;
}
}
Over time, it is likely the number of reducers that you have would increase. In that case, you can combine them via combineReducers
function:
const rootReducer = combineReducers({
counter: counterReducer
});
Now we can create our Store class:
const Store = createStore({
reducer: rootReducer
});
const store = new Store();
const state$ = store.getState$();
state$.subscribe((state) => console.log(state));
You can now dispatch actions via:
store.dispatch(incrementCounter());
Async actions
Not all actions may trigger a synchronous change in state. For those, you can return a function from your action creator.
function incrementCounterAsync() {
return function (dispatch, getState) {
setTimeout(function () {
dispatch(incrementCounter());
}, 3000);
};
}
You can use the thunkArgument
option when defining your Store:
const Store = createStore({
reducer: rootReducer,
thunkArgument: { foo: 'some value' }
});
Now in your async actions, you can access foo
as:
function incrementCounterAsync() {
return function (dispatch, getState, { foo }) {
dispatch(incrementCounter());
};
}
API
createStore
createStore(options)
Arguments
options
(Object
)
options.reducer
(Function
): The reducer function, that returns updated state.options.initialState
(Any
): Default state to start with, defaults to null
.options.console
: Override global console with something custom for logging.options.appendAction
(Object
): Append extra values to Action payload.options.thunkArgument
(Any
): Extra argument to pass to async actions.options.enableLogger
(Boolean
): Enable/disable logging in development mode.
Returns
Store
class.
combineReducers
combineReducers(reducers)
Arguments
reducers
(Object
): Reducer functions keyed by their names
combineReducers({
counter: counterReducer,
list: listReducer,
});
Returns
Function
: The root reducer function.
store
new Store()
The Store instance.
getState
getState()
Returns
Object
: The most recent state, in a synchronous way.
getState$
getState$()
Returns
Observable
: The state as an observable.
dispatch
dispatch(action)
Dispatches the action, which will later trigger changes in state.
Arguments
action
(Object
|Function
): A plain object, with at least a type
key.
The action
argument can also be a function:
function (dispatch, getState, thunkArgument) {
dispatch(actionPayload);
}
Returns
void
.